from typing import Optional, List

from typing_extensions import Self
import pydantic
from pydantic import BaseModel, model_validator


RESOURCE_TYPE_VALUES = (50, 100, 300, 500, 1000, 2000)


class ListReserveMeetingRoomUserInput(BaseModel):
    """
    查询企业预留虚拟会议室成员列表

    :raises: pydantic.ValidationError
    """

    # 操作者用户 ID，必须为企业下具有操作资源权限的注册用户。
    operator_userid: Optional[str] = None

    # 用户 ID，必须为企业下注册用户。
    # 如果使用此参数，用户id不存在时，api查询失败并返回用户不存在错误信息
    userid: Optional[str] = None

    # 用户姓名，必须为企业下注册用户。
    user_name: Optional[int] = None

    # 查询维度，以逗号分隔指定。
    # 1：用户维度
    # 2：部门维度
    # 例如：想要获取部门列表和用户列表，则传入“1,2”。默认只返回用户列表。
    search_types: Optional[str] = '1'

    # 分页查询页码，>= 1
    page: int = 1

    # 分页每页数据数量，1 <= page_size <= 20
    page_size: int = 20

    @model_validator(mode='after')
    def other_validate(self) -> Self:
        if self.search_types not in ['1', '2', '1,2']:
            raise ValueError(
                f'查询企业预留虚拟会议室成员api请求参数校验错误，参数“search_types”的输入值{self.search_types}无效，'
                f'可选值为 "1"、"2"、"1,2"。')

        if self.page < 1:
            raise ValueError(f'查询企业预留虚拟会议室成员api请求参数校验错误，参数“page”的输入值{self.page}无效，必须>=1')

        if not (1 <= self.page_size <= 20):
            raise ValueError(
                f'查询企业预留虚拟会议室成员api请求参数校验错误，参数“page_size”的输入值{self.page_size}无效，必须1-20')

        return self


class PostMeetingRoomUser(BaseModel):
    # 成员 ID
    userid: str

    # 为成员预留的虚拟会议室数量, >= 0
    meeting_room_num: pydantic.NonNegativeInt


class PostMeetingRoomDepartment(BaseModel):
    # 部门 ID
    department_id: str

    # 为部门预留的虚拟会议室数量, >= 0
    meeting_room_num: pydantic.NonNegativeInt


class PostReserveMeetingRoomUserInput(BaseModel):
    """
    设置企业预留虚拟会议室名单

    :raises: pydantic.ValidationError
    """

    # 虚拟会议室资源类型。
    # 默认值为企业当前最小可分配资源类型，为保证资源分配准确，推荐填写虚拟会议室资源类型。
    # 虚拟会议室资源类型有：50、100、300、500、1000、2000，依赖所购买资源的情况。
    resource_type: int

    # 操作者用户 ID，必须为企业下具有操作资源权限的注册用户。
    operator_userid: Optional[str] = None

    # 成员对象列表，必须为企业下的注册用户。不可为免费账号用户预留资源。一次最多处理40个。
    meeting_room_users: Optional[List[PostMeetingRoomUser]] = None

    # 部门对象，一次调用可设置一个部门
    meeting_room_department: Optional[PostMeetingRoomDepartment] = None

    @model_validator(mode='after')
    def other_validate(self) -> Self:
        if self.resource_type not in RESOURCE_TYPE_VALUES:
            raise ValueError(
                f'设置企业预留虚拟会议室名单api请求参数校验错误，参数“resource_type”的输入值{self.resource_type}无效，'
                f'可选值为 {RESOURCE_TYPE_VALUES}。')

        if self.meeting_room_users and len(self.meeting_room_users) > 40:
            raise ValueError(f'设置企业预留虚拟会议室名单api请求参数校验错误，参数“meeting_room_users”的个数最多40')

        return self


class RemoveReserveMeetingRoomUserInput(BaseModel):
    """
    移除企业预留虚拟会议室名单

    :raises: pydantic.ValidationError
    """

    # 移除的虚拟会议室资源类型。
    # 不传入该值，会移除指定用户下的所有预留虚拟会议室资源；若传入该值，只会移除指定的会议室资源。
    # 例如：传入 300，则会移除该用户已预留的 300 方虚拟会议室，对该用户名下预留的 500 方会议室无影响。
    resource_type: int

    # 操作者用户 ID，必须为企业下具有操作资源权限的注册用户。
    operator_userid: Optional[str] = None

    # 企业成员 ID 数组，必须为企业下的注册用户。一次最多处理40个。
    userid_list: Optional[List[str]] = None

    # 部门 ID。每次调用该字段与 userid_list 字段二选一传入。
    department: Optional[str] = None

    @model_validator(mode='after')
    def other_validate(self) -> Self:
        if self.resource_type not in RESOURCE_TYPE_VALUES:
            raise ValueError(
                f'移除企业预留虚拟会议室名单api请求参数校验错误，参数“resource_type”的输入值{self.resource_type}无效，'
                f'可选值为 {RESOURCE_TYPE_VALUES}。')

        if self.userid_list and len(self.userid_list) > 40:
            raise ValueError(f'移除企业预留虚拟会议室名单api请求参数校验错误，参数“userid_list”的个数最多40')

        if self.userid_list and self.department:
            raise ValueError(f'移除企业预留虚拟会议室名单api请求参数校验错误，参数“userid_list”和“department”只能二选一')

        if not self.userid_list and not self.department:
            raise ValueError(f'移除企业预留虚拟会议室名单api请求参数校验错误，参数“userid_list”和“department”必须二选一')

        return self
